package app

import (
	"common/monitor"
	"common/registry"
	service_wrapper "common/service-wrapper"
	"common/util/process"
	"context"
	"github.com/pterm/pterm"
	"os"
	"strconv"
	"syscall"
	"time"
	"xmediaEmu/internal/emu/controller/websocket"
	router "xmediaEmu/internal/emu/controller/websocket"
	. "xmediaEmu/pkg/config"
	log "xmediaEmu/pkg/log"
	"xmediaEmu/pkg/metric"
)

var exitCh chan struct{}

// InitService init rtpProxy func.
func InitService() {
	InitConfig("conf/setting.conf")

	service := Service
	service.Name = AppConf.Api.SrvName
	var nodeSelf = service.Nodes[0]
	nodeSelf.Address = AppConf.Http.Ip
	nodeSelf.Port = AppConf.Http.Port

	// write id to metadata as server-id tag.
	if len(AppConf.Api.ServerId) != 0 {
		nodeSelf.Metadata["serverId"] = AppConf.Api.ServerId
	}
	nodeSelf.Id = AppConf.HttpAddress

	// init log here.
	// log.Init(nodeSelf.Id, log.Config{int32(AppConf.Logger.LogLevel), AppConf.Logger.LogDir, AppConf.Logger.LogPath, AppConf.Logger.LogFiles})
	log.Init(nodeSelf.Id, log.Config{Level: int32(AppConf.Logger.LogLevel), Dir: AppConf.Logger.LogDir, Path: AppConf.Logger.LogPath, FileNum: AppConf.Logger.LogFiles})
	log.Logger.Infof("logger init, log name:%v, LogLevel:%v", AppConf.Logger.LogPath, AppConf.Logger.LogLevel)

	// init recover handler, 远程告警注册, 远程告警服务器不支持微服务.
	// 暂时不加告警.
	process.InitPanicReport(AppConf.Api.SrvName, AppConf.HttpAddress, func(req *process.PanicReq) interface{} {
		return 0
	})

	// init metric here
	metric.InitMetrics(nodeSelf.Id, service.Version)

	router.Init(service.Version)
	monitor.SetMaxCalls((AppConf.Resources.Ports.End - AppConf.Resources.Ports.Start) / 2)

	// 所有初始化工作放这.
	// set core unlimited
	initSysConfig()

	//
	exitCh = make(chan struct{})

	// 初始化监控
	go StartMonitor(exitCh)
}

// StartService 启动主worker线程,x-media作为coordinator.
func StartService() {
	// server id invalid, not register
	var nodeSelf = Service.Nodes[0]
	if len(nodeSelf.Id) < 5 && len(nodeSelf.Id) > 0 {
		if id, err := strconv.Atoi(nodeSelf.Id); err == nil {
			if id < 0 {
				log.Logger.Fatal("StartFail, server not registered, exit=============================")
				return
			}
		}
	}

	// init registry address "/micro-registry"
	prefixName := "/micro-registry"
	if AppConf.Api.ClusterName != "" {
		prefixName = "/" + AppConf.Api.ClusterName + prefixName
	}
	_ = registry.DefaultRegistry.Init(registry.Addrs(AppConf.Registry.Address...), registry.Prefix(prefixName))

	// ws start初始化.
	var ctx context.Context
	ctx, websocket.Handlers.ServiceCancel = context.WithCancel(context.Background())

	// real server.
	server := service_wrapper.NewService(service_wrapper.Address(AppConf.HttpAddress),
		service_wrapper.Engine(websocket.Handlers.Router),
		service_wrapper.ServiceInfo(Service),
		service_wrapper.RegisterInterval(monitor.HeartBeatCheck), service_wrapper.Registry(registry.DefaultRegistry),
		service_wrapper.Context(ctx))

	if err := server.Run(); err != nil {
		log.Logger.Errorf("service StartFail:%v", err)
	}
}

func StopService() {
	log.Logger.Info("Session is stopping...")
	close(exitCh)

	// 其他模块停服务操作.
	// 如ws模块停止.
}

// StartMonitor modify service info to servers..
// not used any more
// TODO: 需要增加自己的实例监控, 比如当前的ws实例数.
func StartMonitor(exit chan struct{}) {
	t := time.NewTicker(monitor.HeartBeatCheck)
	// sessionManage, _ := rtpproxy.GetSessionMgr()
	defer func() {
		// here must move to the record file function
		if v := recover(); v != nil {
			process.DefaultPanicReport.RecoverFromPanic("", "startMonitor", v)
		}
	}()

	// to add ping prometheus monitor goroutines.
	for {
		select {
		case <-t.C:
			if IsPause() {
				continue
			}
			// monitor.UpdateServiceWithoutSync(Service, sessionManage.Size())
		case <-exit:
			t.Stop()

			return
		}
	}
}

func initSysConfig() {
	// set core unlimited
	var ulimitSize uint64
	ulimitSize = 0x7FFFFFFFFF
	rlimit := &syscall.Rlimit{ulimitSize, ulimitSize}
	if err := syscall.Setrlimit(syscall.RLIMIT_CORE, rlimit); err != nil {
		log.Logger.Errorf("MediaServer StartFail, syscall.Setrlimit failed:%v", err)
		pterm.FgLightRed.Printf("MediaServer StartFail, syscall.Setrlimit failed:%s\n", err.Error())
		os.Exit(-1)
	}

	if err := syscall.Getrlimit(syscall.RLIMIT_CORE, rlimit); err != nil {
		log.Logger.Errorf("MediaServer StartFail, syscall.Getrlimit failed:%v", err)
		pterm.FgLightRed.Printf("MediaServer StartFail, syscall.Getrlimit failed:%s\n", err.Error())
		os.Exit(-1)
	}
	log.Logger.Infof("After set rlimit CORE dump current is:%v, max is:%v", rlimit.Cur, rlimit.Max)
	pterm.FgYellow.Printf("After set rlimit CORE dump current is:%d, max is:%d\n", rlimit.Cur, rlimit.Max)

	// open files
	rlimit.Cur = 0x7FFFF
	rlimit.Max = 0x7FFFF
	if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, rlimit); err != nil {
		log.Logger.Errorf("XMedia StartFail, syscall.Setrlimit failed:%v", err)
		os.Exit(-1)
	}
	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rlimit); err != nil {
		log.Logger.Errorf("XMedia StartFail, syscall.Getrlimit failed:%v", err)
		os.Exit(-1)
	}
	log.Logger.Infof("After set rlimit RLIMIT_NOFILE current is:%v, max is:%v", rlimit.Cur, rlimit.Max)
	pterm.FgYellow.Printf("After set rlimit RLIMIT_NOFILE current is:%d, max is:%d\n", rlimit.Cur, rlimit.Max)

	tempEnv := os.Getenv("GOTRACEBACK")
	log.Logger.Infof("os.GetEnv GOTRACEBACK is:%v", tempEnv)
}
